home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / quicktimeintro / wiredsprites / common files / qtutilities.c < prev    next >
Encoding:
Text File  |  2000-10-06  |  54.0 KB  |  1,888 lines

  1. //////////
  2. //
  3. //    File:        QTUtilities.c
  4. //
  5. //    Contains:    Some utilities for working with QuickTime movies.
  6. //                All utilities start with the prefix "QTUtils_".
  7. //
  8. //    Written by:    Tim Monroe
  9. //                Based on the DTSQTUtilities package by Apple DTS.
  10. //                This began as essentially a subset of that package, revised for cross-platform use.
  11. //
  12. //    Copyright:    © 1996-1999 by Apple Computer, Inc., all rights reserved.
  13. //
  14. //    Change History (most recent first):
  15. //
  16. //       <33>         03/08/00    rtm        removed QTUtils_SaveMovie and QTUtils_PrintMoviePICT
  17. //       <32>         03/02/00    rtm        added QTUtils_SelectNoneMovie
  18. //       <31>         01/10/00    rtm        tweaked QTUtils_IsQuickTimeInstalled
  19. //       <30>         12/20/99    rtm        reworked QTUtils_IsMovieFile, to first test for files of type kQTFileTypeMovie
  20. //       <29>         12/09/99    rtm        added QTUtils_PutControllerBarOnTop
  21. //       <28>         12/08/99    rtm        reworked controller button functions to support custom buttom (its mcFlags constant
  22. //                                    is a "Use" constant and not a "Suppress" constant)
  23. //       <27>         11/26/99    rtm        added endian adjustments to _GetMovieFileLoopingInfo and _GetWindowPositionFromFile
  24. //       <26>         11/17/99    rtm        added QTUtils_GetWindowPositionFromFile
  25. //       <25>         05/19/99    rtm        removed QTUtils_GetMovie
  26. //       <24>         05/10/99    rtm        added QTUtils_UpdateMovieVolumeSetting
  27. //       <23>         03/22/99    rtm        updated connection speed code to use constants/data types now in Movies.h
  28. //       <22>         03/11/99    rtm        moved _GetControllerType and _SetControllerType from QTVRUtilities to here;
  29. //                                    added QTUtils_ChangeControllerType
  30. //       <21>         02/03/99    rtm        moved non-QTVR-specific utilities from QTVRUtilities to here
  31. //       <20>         01/26/99    rtm        added QTUtils_ConvertCToPascalString; removed "\p" from any constant strings
  32. //       <19>         01/25/99    rtm        #define'd away QTUtils_GetUsersContentRating and siblings, since content rating
  33. //                                    capability is not in latest feature set
  34. //       <18>         12/09/98    rtm        added QTUtils_GetUsersContentRating
  35. //       <17>         11/18/98    rtm        added QTUtils_GetFrameCount
  36. //       <16>         10/27/98    rtm        added QTUtils_MakeMovieLoop
  37. //       <15>         09/14/98    rtm        added QTUtils_GetUsersConnectionSpeed and QTUtils_SetUsersConnectionSpeed
  38. //       <14>         06/24/98    rtm        added QTUtils_GetMaxWindowDepth and QTUtils_GetMaxScreenDepth
  39. //       <13>         06/04/98    rtm        added QTUtils_DeleteAllReferencesToTrack
  40. //       <12>         05/28/98    rtm        added some typecasting to minimize MSDev compiler warnings
  41. //       <11>         05/19/98    rtm        added QTUtils_MovieHasTimeCodeTrack
  42. //       <10>         05/04/98    rtm        added QTUtils_GetTrackName, QTUtils_SetTrackName, QTUtils_MakeTrackNameByType,
  43. //                                    QTUtils_IsImageFile, and QTUtils_IsMovieFile
  44. //       <9>         02/28/98    rtm        fixed QTUtils_GetMovieFileLoopingInfo and the like
  45. //       <8>         01/14/98    rtm        added QTUtils_ConvertFloatToBigEndian
  46. //       <7>         12/19/97    rtm        added QTUtils_AddUserDataTextToMovie and associated routines;
  47. //                                    added QTUtils_GetMovieFileLoopingInfo and the like
  48. //       <6>         11/06/97    rtm        added QTUtils_MakeSampleDescription
  49. //       <5>         10/29/97    rtm        modified QTUtils_IsMediaTypeInMovie and similar routines to use GetMovieIndTrackType
  50. //       <4>         10/27/97    rtm        added QTUtils_HasQuickTimeVideoEffects
  51. //       <3>         10/17/97    rtm        added QTUtils_MovieHasSoundTrack
  52. //       <2>         09/23/97    rtm        added endian adjustment to QTUtils_PrintMoviePICT
  53. //       <1>         09/10/97    rtm        first file
  54. //       
  55. //////////
  56.  
  57. //////////
  58. //
  59. // header files
  60. //
  61. //////////
  62.  
  63. #ifndef __QTUtilities__
  64. #include "QTUtilities.h"
  65.  
  66.  
  67. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  68. //
  69. // General utilities.
  70. //
  71. // Use these functions to get information about the availability/features of QuickTime or other services.
  72. //
  73. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  74.  
  75. //////////
  76. //
  77. // QTUtils_TrapAvailable
  78. // Check to see whether a given trap is implemented. This is based on IM: Operating System Utilities (p. 8-22).
  79. //
  80. //////////
  81.  
  82. #if TARGET_OS_MAC && !TARGET_API_MAC_CARBON
  83. Boolean QTUtils_TrapAvailable (short theTrapWord)
  84. {
  85.     TrapType        myTrapType;
  86.     short            myNumToolboxTraps;
  87.     
  88.     // determine whether this is a Toolbox or an Operating System trap
  89.     if ((theTrapWord & 0x0800) > 0)
  90.         myTrapType = ToolTrap;
  91.     else
  92.         myTrapType = OSTrap;
  93.  
  94.     if (myTrapType == ToolTrap) {
  95.         theTrapWord = theTrapWord & 0x07FF;
  96.         
  97.         if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  98.             myNumToolboxTraps = 0x0200;
  99.         else
  100.             myNumToolboxTraps = 0x0400;
  101.             
  102.         if (theTrapWord >= myNumToolboxTraps)
  103.             theTrapWord = _Unimplemented;
  104.     }
  105.  
  106.     return(NGetTrapAddress(theTrapWord, myTrapType) != NGetTrapAddress(_Unimplemented, ToolTrap));
  107. }
  108. #endif
  109.  
  110.  
  111. //////////
  112. //
  113. // QTUtils_IsQuickTimeInstalled
  114. // Is QuickTime installed?
  115. //
  116. //////////
  117.  
  118. Boolean QTUtils_IsQuickTimeInstalled (void) 
  119. {
  120.     long        myAttrs;
  121.     OSErr         myErr = noErr;
  122.  
  123.     myErr = Gestalt(gestaltQuickTime, &myAttrs);
  124.  
  125.     return(myErr == noErr);
  126. }
  127.  
  128.  
  129. //////////
  130. //
  131. // QTUtils_IsQuickTimeCFMInstalled
  132. // Are the QuickTime CFM libraries installed?
  133. //
  134. //////////
  135.  
  136. #if TARGET_CPU_PPC
  137. Boolean QTUtils_IsQuickTimeCFMInstalled (void) 
  138. {
  139.     Boolean     myQTCFMAvail = false;
  140.     long        myAttrs;
  141.     OSErr         myErr = noErr;
  142.  
  143.     // test whether the PowerPC QuickTime glue library is present
  144.     myErr = Gestalt(gestaltQuickTimeFeatures, &myAttrs);
  145.     if (myErr == noErr)
  146.         if (myAttrs & (1L << gestaltPPCQuickTimeLibPresent))
  147.             myQTCFMAvail = true;
  148.  
  149.     // test whether a function is available (the library is not moved from the Extension folder);
  150.     // this is the trick to be used when testing if a function is available via CFM
  151.     if (!CompressImage)
  152.         myQTCFMAvail = false;     
  153.  
  154.     return(myQTCFMAvail);
  155. }
  156. #endif
  157.  
  158.  
  159. //////////
  160. //
  161. // QTUtils_GetQTVersion
  162. // Get the version of QuickTime installed.
  163. // The high-order word of the returned long integer contains the version number,
  164. // so you can test a version like this:
  165. //
  166. //        if (((QTUtils_GetQTVersion() >> 16) & 0xffff) >= 0x0210)        // we require QT 2.1 or greater
  167. //            return;
  168. //
  169. //////////
  170.  
  171. long QTUtils_GetQTVersion (void) 
  172. {
  173.     long         myVersion = 0L;
  174.     OSErr         myErr = noErr;
  175.  
  176.     myErr = Gestalt(gestaltQuickTime, &myVersion);
  177.     if (myErr == noErr)
  178.         return(myVersion);
  179.     else
  180.         return(0L);
  181. }
  182.  
  183.  
  184. //////////
  185. //
  186. // QTUtils_HasQuickTimeVideoEffects
  187. // Does the installed version of QuickTime support video effects?
  188. //
  189. // Note: this is a pretty cheesy way of determining whether video effects are available.
  190. //
  191. //////////
  192.  
  193. Boolean QTUtils_HasQuickTimeVideoEffects (void) 
  194. {
  195.     return(((QTUtils_GetQTVersion() >> 16) & 0xffff) >= kQTVideoEffectsMinVers);
  196. }
  197.  
  198.  
  199. //////////
  200. //
  201. // QTUtils_HasFullScreenSupport
  202. // Does the installed version of QuickTime support the full-screen routines?
  203. //
  204. // Note: this is a pretty cheesy way of determining whether full-screen routines are available.
  205. //
  206. //////////
  207.  
  208. Boolean QTUtils_HasFullScreenSupport (void) 
  209. {
  210.     return(((QTUtils_GetQTVersion() >> 16) & 0xffff) >= kQTFullScreenMinVers);
  211. }
  212.  
  213.  
  214. //////////
  215. //
  216. // QTUtils_HasWiredSprites
  217. // Does the installed version of QuickTime support wired sprites?
  218. //
  219. // Note: this is a pretty cheesy way of determining whether wired sprites are available.
  220. //
  221. //////////
  222.  
  223. Boolean QTUtils_HasWiredSprites (void) 
  224. {
  225.     return(((QTUtils_GetQTVersion() >> 16) & 0xffff) >= kQTWiredSpritesMinVers);
  226. }
  227.  
  228.  
  229. //////////
  230. //
  231. // QTUtils_IsQTVRMovie
  232. // Is the specified movie a QTVR movie?
  233. //
  234. // WARNING: This function is intended for use ONLY when you want to determine if you've got a QTVR movie
  235. // but you don't want to use the QuickTime VR API (perhaps QTVR isn't installed...). The preferred way to
  236. // determine if a movie is a QTVR movie is to call QTVRGetQTVRTrack and then QTVRGetQTVRInstance; if you
  237. // get back a non-NULL instance, you've got a QTVR movie.
  238. //
  239. //////////
  240.  
  241. Boolean QTUtils_IsQTVRMovie (Movie theMovie) 
  242. {
  243.     Boolean            myIsQTVRMovie = false;
  244.     OSType            myType;
  245.     
  246.     // QTVR movies have a special piece of user data identifying the movie controller type
  247.     myType = QTUtils_GetControllerType(theMovie);
  248.     
  249.     if ((myType == kQTVRQTVRType) || (myType == kQTVROldPanoType) || (myType == kQTVROldObjectType))
  250.         myIsQTVRMovie = true; 
  251.         
  252.     return(myIsQTVRMovie);
  253. }
  254.  
  255.  
  256. //////////
  257. //
  258. // QTUtils_IsStreamedMovie
  259. // Is the specified movie a streamed movie?
  260. //
  261. //////////
  262.  
  263. Boolean QTUtils_IsStreamedMovie (Movie theMovie) 
  264. {
  265.     return(GetMovieIndTrackType(theMovie, 1, kQTSStreamMediaType, movieTrackMediaType | movieTrackEnabledOnly) != NULL);
  266. }
  267.  
  268.  
  269. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  270. //
  271. // Controller bar utilities.
  272. //
  273. // Use these functions to manipulate the controller bar, its buttons, and the help text displayed in it.
  274. //
  275. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  276.  
  277. //////////
  278. //
  279. // QTUtils_IsControllerBarVisible
  280. // Is the controller bar currently visible?
  281. //
  282. //////////
  283.  
  284. Boolean QTUtils_IsControllerBarVisible (MovieController theMC) 
  285. {
  286.     return((Boolean)MCGetVisible(theMC));
  287. }
  288.  
  289.  
  290. //////////
  291. //
  292. // QTUtils_GetControllerBarHeight
  293. // Return the height of the controller bar displayed by the movie controller.
  294. //
  295. // Note that MCGetControllerBoundsRect returns the rectangle of bar and movie, if attached;
  296. // so we need to detach the controller bar first.
  297. //
  298. //////////
  299.  
  300. short QTUtils_GetControllerBarHeight (MovieController theMC) 
  301. {
  302.     Boolean        wasAttached = false;
  303.     Rect        myRect;
  304.     
  305.     // if the controller bar is attached, detach it (and remember we did so)
  306.     if (MCIsControllerAttached(theMC) == 1) {
  307.         wasAttached = true;
  308.         MCSetControllerAttached(theMC, false);
  309.     }
  310.     
  311.     // get the rectangle of the controller
  312.     MCGetControllerBoundsRect(theMC, &myRect);
  313.     
  314.     // now reattach the controller bar, if it was originally attached
  315.     if (wasAttached)
  316.         MCSetControllerAttached(theMC, true);
  317.     
  318.     return(myRect.bottom - myRect.top);
  319. }
  320.  
  321.  
  322. //////////
  323. //
  324. // QTUtils_HideControllerBar
  325. // Hide the controller bar provided by the movie controller.
  326. //
  327. //////////
  328.  
  329. void QTUtils_HideControllerBar (MovieController theMC) 
  330. {
  331.     MCSetVisible(theMC, false);
  332. }
  333.  
  334.  
  335. //////////
  336. //
  337. // QTUtils_ShowControllerBar
  338. // Show the controller bar provided by the movie controller.
  339. //
  340. //////////
  341.  
  342. void QTUtils_ShowControllerBar (MovieController theMC) 
  343. {
  344.     MCSetVisible(theMC, true);
  345. }
  346.  
  347.  
  348. //////////
  349. //
  350. // QTUtils_ToggleControllerBar
  351. // Toggle the state of the controller bar provided by the movie controller.
  352. //
  353. //////////
  354.  
  355. void QTUtils_ToggleControllerBar (MovieController theMC) 
  356. {
  357.     if (QTUtils_IsControllerBarVisible(theMC))
  358.         QTUtils_HideControllerBar(theMC);
  359.     else
  360.         QTUtils_ShowControllerBar(theMC);
  361. }
  362.  
  363.  
  364. //////////
  365. //
  366. // QTUtils_PutControllerBarOnTop
  367. // Put the movie controller bar at the top of the movie window.
  368. //
  369. //////////
  370.  
  371. void QTUtils_PutControllerBarOnTop (MovieController theMC) 
  372. {
  373.     if (theMC == NULL)
  374.         return;
  375.         
  376.     if (MCIsControllerAttached(theMC) == 1) {
  377.         Rect        myMCRect;
  378.         Rect        myMovieRect;
  379.                         
  380.         MCGetControllerBoundsRect(theMC, &myMCRect);
  381.         myMovieRect = myMCRect;
  382.         myMCRect.bottom = myMCRect.top + QTUtils_GetControllerBarHeight(theMC);
  383.         myMovieRect.top = myMCRect.bottom + 1;
  384.         
  385.         MCSetControllerAttached(theMC, false);
  386.         
  387.         MCPositionController(theMC, &myMovieRect, &myMCRect, 0L);
  388.     }
  389. }
  390.  
  391.  
  392. //////////
  393. //
  394. // QTUtils_HideControllerButton
  395. // Hide the specified button in the controller bar.
  396. //
  397. // Some explanation is probably useful here: the first thing to understand is that every VR movie has 
  398. // TWO sets of movie controller flags: (1) a set of "control flags" and (2) a set of "explicit flags".
  399. //
  400. // The control flags work as documented in IM: QuickTime Components (pp. 2-20f) and in VRPWQTVR2.0 (pp. 2-23f):
  401. // if a bit in the set of control flags is set (that is, equal to 1), then the associated action or property is
  402. // enabled. For instance, bit 17 (mcFlagQTVRSuppressZoomBtns) means to suppress the zoom buttons. So, if that
  403. // bit is set in a VR movie's control flags, the zoom buttons are NOT displayed. If that bit is clear, the zoom
  404. // buttons are displayed.
  405. //
  406. // However, the QuickTime VR movie controller sometimes suppresses buttons even when those buttons 
  407. // have not been explicitly suppressed in the control flags. For example, if a particular VR movie does not
  408. // contain a sound track, then the movie controller automatically suppresses the speaker/volume button. Likewise,
  409. // if a movie does contain a sound track, then the speaker/volume button is automatically displayed, again without
  410. // regard to the actual value of bit 2 in the control flags.
  411. //
  412. // This might not be what you'd like to happen. For instance, if your application is playing a sound that it
  413. // loaded from a sound resource, you might want the user to be able to adjust the sound's volume using the volume
  414. // control. To do that, you need a way to *force* the speaker/volume button to appear. For this reason, the
  415. // explicit flags were introduced.
  416. //
  417. // The explicit flags indicate which bits in the control flags are to be used explicitly (that is, taken at
  418. // face value). If a certain bit is set in a movie's explicit flags, then the corresponding bit in the control
  419. // flags is interpreted as the desired setting for the feature (and the movie controller will not attempt to
  420. // do anything "clever"). In other words, if bit 17 is set in a movie's explicit flags and bit 17 is clear in
  421. // that movie's control flags, then the zoom buttons are displayed. Similarly, if bit 2 is set in a movie's 
  422. // explicit flags and bit 2 is clear in that movie's control flags, then the speaker/volume button is displayed,
  423. // whether or not the movie contains a sound track.
  424. //
  425. // The final thing to understand: to get or set a bit in a movie's explicit flags, you must set the flag 
  426. // mcFlagQTVRExplicitFlagSet in your call to mcActionGetFlags or mcActionSetFlags. To get or set a bit in a 
  427. // movie's control flags, you must clear the flag mcFlagQTVRExplicitFlagSet in your call to mcActionGetFlags 
  428. // or mcActionSetFlags. Note that when you use the defined constants to set values in the explicit flags, the 
  429. // constant names might be confusing. For instance, setting the bit mcFlagSuppressSpeakerButton in a movie's
  430. // explicit flags doesn't cause the speaker to be suppressed; it just means: "use the actual value of the
  431. // mcFlagSuppressSpeakerButton bit in the control flags".
  432. //
  433. // Whew! Any questions? Okay, then now you'll understand how to hide or show a button in the controller bar:
  434. // set the appropriate explicit flag to 1 and set the corresponding control flag to the desired value. And
  435. // you'll understand how to let the movie controller do its "clever" work: clear the appropriate explicit flag.
  436. //
  437. // There is one final twist to this story: the mcFlag bit for the custom controller button indicates that the
  438. // custom button should be shown, not (like all other button flags) that the button should be suppressed. So
  439. // we need to treat the custom button specially. Sigh.
  440. //
  441. //////////
  442.  
  443. void QTUtils_HideControllerButton (MovieController theMC, long theButton) 
  444. {
  445.     long    myControllerFlags;
  446.     
  447.     // handle the custom button separately
  448.     if (theButton == kQTUtilsCustomButton) {
  449.         MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  450.         MCDoAction(theMC, mcActionSetFlags, (void *)(myControllerFlags & ~theButton));
  451.     } else {
  452.         // get the current explicit flags and set the explicit flag for the specified button
  453.         myControllerFlags = mcFlagQTVRExplicitFlagSet;
  454.         MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  455.         MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) | mcFlagQTVRExplicitFlagSet));
  456.         
  457.         // get the current control flags and set the suppress flag for the specified button
  458.         myControllerFlags = 0;
  459.         MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  460.         MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) & ~mcFlagQTVRExplicitFlagSet));
  461.     }
  462. }
  463.  
  464.  
  465. //////////
  466. //
  467. // QTUtils_ShowControllerButton
  468. // Show the specified button in the controller bar.
  469. //
  470. //////////
  471.  
  472. void QTUtils_ShowControllerButton (MovieController theMC, long theButton) 
  473. {
  474.     long    myControllerFlags;
  475.     
  476.     // handle the custom button separately
  477.     if (theButton == kQTUtilsCustomButton) {
  478.         MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  479.         MCDoAction(theMC, mcActionSetFlags, (void *)(myControllerFlags | theButton));
  480.     } else {
  481.         // get the current explicit flags and set the explicit flag for the specified button
  482.         myControllerFlags = mcFlagQTVRExplicitFlagSet;
  483.         MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  484.         MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) | mcFlagQTVRExplicitFlagSet));
  485.         
  486.         // get the current control flags and clear the suppress flag for the specified button
  487.         myControllerFlags = 0;
  488.         MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  489.         MCDoAction(theMC, mcActionSetFlags, (void *)(myControllerFlags & ~theButton & ~mcFlagQTVRExplicitFlagSet));
  490.     }
  491. }
  492.  
  493.  
  494. //////////
  495. //
  496. // QTUtils_ToggleControllerButton
  497. // Toggle the state of the specified button in the controller bar.
  498. //
  499. //////////
  500.  
  501. void QTUtils_ToggleControllerButton (MovieController theMC, long theButton) 
  502. {
  503.     if (QTUtils_IsControllerButtonVisible(theMC, theButton))    
  504.         QTUtils_HideControllerButton(theMC, theButton);
  505.     else
  506.         QTUtils_ShowControllerButton(theMC, theButton);
  507. }
  508.  
  509.  
  510. //////////
  511. //
  512. // QTUtils_ResetControllerButton
  513. // Remove any explicit setting of the specified button in the controller bar.
  514. // (This allows the QuickTime VR movie controller to be as clever as it knows how to be.)
  515. //
  516. //////////
  517.  
  518. void QTUtils_ResetControllerButton (MovieController theMC, long theButton) 
  519. {
  520.     long    myControllerFlags = mcFlagQTVRExplicitFlagSet;
  521.     
  522.     // get the current explicit flags and clear the explicit flag for the specified button
  523.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  524.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) & ~mcFlagQTVRExplicitFlagSet));
  525. }
  526.  
  527.  
  528. //////////
  529. //
  530. // QTUtils_IsControllerButtonVisible
  531. // Is the specified button in the controller bar currently visible?
  532. //
  533. //////////
  534.  
  535. Boolean QTUtils_IsControllerButtonVisible (MovieController theMC, long theButton) 
  536. {
  537.     long        myControllerFlags;
  538.  
  539.     // get the current control flags
  540.     myControllerFlags = 0;
  541.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  542.  
  543.     // the speaker button requires some additional logic, because the QTVR movie controller treats it special;
  544.     // be advised that that controller's special behavior could change in the future, so you might need to tweak this code
  545.     if (theButton == mcFlagSuppressSpeakerButton) {
  546.         long    myExplicitFlags;
  547.         
  548.         // get the current explicit flags
  549.         myExplicitFlags = mcFlagQTVRExplicitFlagSet;
  550.         MCDoAction(theMC, mcActionGetFlags, &myExplicitFlags);
  551.     
  552.         // the speaker button is not showing if the movie has no sound track and the explicit flag is not set
  553.         if (!QTUtils_MovieHasSoundTrack(MCGetMovie(theMC)) && !(myExplicitFlags & theButton))
  554.             return(false);
  555.     }
  556.     
  557.     // the custom button requires some different treatment, since it doesn't have a "Suppress" button constant
  558.     if (theButton == mcFlagsUseCustomButton)
  559.         if (myControllerFlags & theButton)
  560.             return(true);
  561.         else
  562.             return(false);
  563.     
  564.     // examine the suppress flag for the specified button
  565.     if (myControllerFlags & theButton)                // if the button is currently suppressed...
  566.         return(false);
  567.     else
  568.         return(true);
  569. }
  570.  
  571.  
  572. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  573. //
  574. // Media utilities.
  575. //
  576. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  577.  
  578. //////////
  579. //
  580. // QTUtils_IsMediaTypeInMovie
  581. // Determine whether a specific media type is in a movie.
  582. // 
  583. //////////
  584.  
  585. Boolean QTUtils_IsMediaTypeInMovie (Movie theMovie, OSType theMediaType)
  586. {
  587.     return(GetMovieIndTrackType(theMovie, 1, theMediaType, movieTrackMediaType | movieTrackEnabledOnly) != NULL);
  588. }
  589.  
  590.  
  591. //////////
  592. //
  593. // QTUtils_MovieHasTimeCodeTrack
  594. // Determine whether a movie contains a timecode track.
  595. // 
  596. //////////
  597.  
  598. Boolean QTUtils_MovieHasTimeCodeTrack (Movie theMovie)
  599. {
  600.     return(GetMovieIndTrackType(theMovie, 1, TimeCodeMediaType, movieTrackMediaType) != NULL);
  601. }
  602.  
  603.  
  604. //////////
  605. //
  606. // QTUtils_MovieHasSoundTrack
  607. // Determine whether a movie contains a sound track.
  608. // 
  609. //////////
  610.  
  611. Boolean QTUtils_MovieHasSoundTrack (Movie theMovie)
  612. {
  613.     return(GetMovieIndTrackType(theMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly) != NULL);
  614. }
  615.  
  616.  
  617. //////////
  618. //
  619. // QTUtils_GetSoundMediaHandler
  620. // Return the sound media handler for a movie.
  621. // 
  622. //////////
  623.  
  624. MediaHandler QTUtils_GetSoundMediaHandler (Movie theMovie)
  625. {
  626.     Track        myTrack;
  627.     Media        myMedia;
  628.  
  629.     myTrack = GetMovieIndTrackType(theMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
  630.     if (myTrack != NULL) {
  631.         myMedia = GetTrackMedia(myTrack);
  632.         return(GetMediaHandler(myMedia));
  633.     } 
  634.         
  635.     return(NULL);
  636. }
  637.  
  638.  
  639. //////////
  640. //
  641. // QTUtils_UpdateMovieVolumeSetting
  642. // Update the preferred volume setting of the specified movie.
  643. // 
  644. //////////
  645.  
  646. OSErr QTUtils_UpdateMovieVolumeSetting (Movie theMovie)
  647. {
  648.     short            myPrefVolume;
  649.     short            myCurrVolume;
  650.     OSErr            myErr = noErr;
  651.     
  652.     myPrefVolume = GetMoviePreferredVolume(theMovie);
  653.     myCurrVolume = GetMovieVolume(theMovie);
  654.     myCurrVolume = abs(myCurrVolume);
  655.     
  656.     if (myPrefVolume != myCurrVolume) {
  657.         SetMoviePreferredVolume(theMovie, myCurrVolume);
  658.         myErr = GetMoviesError();
  659.     }
  660.     
  661.     return(myErr);
  662. }
  663.  
  664.  
  665. //////////
  666. //
  667. // QTUtils_SelectAllMovie
  668. // Select the entire movie associated with the specified movie controller.
  669. // 
  670. //////////
  671.  
  672. OSErr QTUtils_SelectAllMovie (MovieController theMC)
  673. {
  674.     TimeRecord            myTimeRecord;
  675.     Movie                 myMovie = NULL;
  676.     ComponentResult        myErr = noErr;
  677.     
  678.     if (theMC == NULL)
  679.         return(paramErr);
  680.     
  681.     myMovie = MCGetMovie(theMC);
  682.     if (myMovie == NULL)
  683.         return(paramErr);
  684.     
  685.     myTimeRecord.value.hi = 0;
  686.     myTimeRecord.value.lo = 0;
  687.     myTimeRecord.base = 0;
  688.     myTimeRecord.scale = GetMovieTimeScale(myMovie);    
  689.     myErr = MCDoAction(theMC, mcActionSetSelectionBegin, &myTimeRecord);
  690.     if (myErr != noErr)
  691.         return((OSErr)myErr);
  692.     
  693.     myTimeRecord.value.hi = 0;
  694.     myTimeRecord.value.lo = GetMovieDuration(myMovie);    
  695.     myTimeRecord.base = 0;
  696.     myTimeRecord.scale = GetMovieTimeScale(myMovie);    
  697.     myErr = MCDoAction(theMC, mcActionSetSelectionDuration, &myTimeRecord);
  698.     
  699.     return((OSErr)myErr);
  700. }
  701.  
  702.  
  703. //////////
  704. //
  705. // QTUtils_SelectNoneMovie
  706. // Select none of the movie associated with the specified movie controller.
  707. // 
  708. //////////
  709.  
  710. OSErr QTUtils_SelectNoneMovie (MovieController theMC)
  711. {
  712.     TimeRecord            myTimeRecord;
  713.     Movie                 myMovie = NULL;
  714.     ComponentResult        myErr = noErr;
  715.     
  716.     if (theMC == NULL)
  717.         return(paramErr);
  718.     
  719.     myMovie = MCGetMovie(theMC);
  720.     if (myMovie == NULL)
  721.         return(paramErr);
  722.     
  723.     myTimeRecord.value.hi = 0;
  724.     myTimeRecord.value.lo = 0;    
  725.     myTimeRecord.base = 0;
  726.     myTimeRecord.scale = GetMovieTimeScale(myMovie);    
  727.     myErr = MCDoAction(theMC, mcActionSetSelectionDuration, &myTimeRecord);
  728.     
  729.     return((OSErr)myErr);
  730. }
  731.  
  732.  
  733. //////////
  734. //
  735. // QTUtils_MakeSampleDescription
  736. // Return a new image description with default and specified values.
  737. // 
  738. //////////
  739.  
  740. ImageDescriptionHandle QTUtils_MakeSampleDescription (long theEffectType, short theWidth, short theHeight)
  741. {
  742.     ImageDescriptionHandle        mySampleDesc = NULL;
  743.     OSErr                        myErr = noErr;
  744.  
  745.     // create a new sample description
  746.     mySampleDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  747.     if (mySampleDesc == NULL)
  748.         return(NULL);
  749.     
  750.     // fill in the fields of the sample description
  751.     (**mySampleDesc).idSize = sizeof(ImageDescription);
  752.     (**mySampleDesc).cType = theEffectType;
  753.     (**mySampleDesc).vendor = kAppleManufacturer;
  754.     (**mySampleDesc).temporalQuality = codecNormalQuality;
  755.     (**mySampleDesc).spatialQuality = codecNormalQuality;
  756.     (**mySampleDesc).width = theWidth;
  757.     (**mySampleDesc).height = theHeight;
  758.     (**mySampleDesc).hRes = 72L << 16;
  759.     (**mySampleDesc).vRes = 72L << 16;
  760.     (**mySampleDesc).dataSize = 0L;
  761.     (**mySampleDesc).frameCount = 1;
  762.     (**mySampleDesc).depth = 24;
  763.     (**mySampleDesc).clutID = -1;
  764.     
  765.     return(mySampleDesc);
  766. }
  767.  
  768.  
  769. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  770. //
  771. // User data utilities.
  772. //
  773. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  774.  
  775. #if CONTENT_RATING_AVAIL
  776. //////////
  777. //
  778. // QTUtils_GetContentRatingFromMovie
  779. // Get the content rating from a movie; return an error if it has none. In any case, return a meaningful
  780. // content rating.
  781. //
  782. //////////
  783.  
  784. OSErr QTUtils_GetContentRatingFromMovie (Movie theMovie, UInt16 *theRating, UInt32 *theReasons)
  785. {
  786.     UserData                    myUserData = NULL;
  787.     QTAltContentRatingRecord    myContentRec;
  788.     OSErr                        myErr = paramErr;
  789.  
  790.     *theRating = kQTContentTVYRating;
  791.     *theReasons = 0L;
  792.  
  793.     // make sure we've got a movie
  794.     if (theMovie == NULL)
  795.         return(myErr);
  796.         
  797.     // get the movie's user data list
  798.     myUserData = GetMovieUserData(theMovie);
  799.     if (myUserData != NULL) {
  800.         myErr = GetUserDataItem(myUserData, &myContentRec, sizeof(myContentRec), FOUR_CHAR_CODE('crat'), 0);
  801.         if (myErr == noErr) {
  802.             *theRating = EndianU16_BtoN(myContentRec.ratings);
  803.             *theReasons = EndianU32_BtoN(myContentRec.contentType);
  804.         }
  805.     }
  806.  
  807.     return(myErr);
  808. }
  809.  
  810.  
  811. //////////
  812. //
  813. // QTUtils_AddContentRatingToMovie
  814. // Add a content rating to a movie.
  815. //
  816. // A content rating is stored as a user data item that indicates both the general rating
  817. // (for example, TV-MA [mature audiences only]) and any additional information about the
  818. // content (for example, coarse language). Let's call this additional information the
  819. // "reasons" for the rating. Both the rating and the reasons are specified using constants
  820. // in the file MoviesFormat.h.
  821. //
  822. // This function adds the specified content rating to the movie's user data;
  823. // the updated user data is written to the movie file when the movie is next updated
  824. // (by calling UpdateMovieResource).
  825. // 
  826. //////////
  827.  
  828. OSErr QTUtils_AddContentRatingToMovie (Movie theMovie, UInt16 theRating, UInt32 theReasons)
  829. {
  830.     UserData                    myUserData = NULL;
  831.     QTAltContentRatingRecord    myContentRec;
  832.     OSErr                        myErr = noErr;
  833.  
  834.     // get the movie's user data list
  835.     myUserData = GetMovieUserData(theMovie);
  836.     if (myUserData == NULL)
  837.         return(paramErr);
  838.     
  839.     myContentRec.flags = 0;
  840.     myContentRec.contentType = EndianU32_NtoB(theReasons);
  841.     myContentRec.ratings = EndianU16_NtoB(theRating);
  842.     
  843.     // for simplicity, we assume that we want only one content rating in the movie;
  844.     // as a result, we won't worry about overwriting any existing item of that type
  845.  
  846.     // add the data to the movie's user data
  847.     myErr = SetUserDataItem(myUserData, &myContentRec, sizeof(myContentRec), FOUR_CHAR_CODE('crat'), 0);
  848.  
  849.     return(myErr);
  850. }
  851. #endif    // #if CONTENT_RATING_AVAIL
  852.  
  853.  
  854. //////////
  855. //
  856. // QTUtils_AddUserDataTextToMovie
  857. // Add a user data item, of the specified type, containing the specified text to a movie.
  858. //
  859. // This function adds the specified text to the movie's user data;
  860. // the updated user data is written to the movie file when the movie is next updated
  861. // (by calling UpdateMovieResource).
  862. // 
  863. //////////
  864.  
  865. OSErr QTUtils_AddUserDataTextToMovie (Movie theMovie, char *theText, OSType theType)
  866. {
  867.     UserData                    myUserData = NULL;
  868.     Handle                        myHandle = NULL;
  869.     short                        myIndex = 0;
  870.     long                        myLength = strlen(theText);
  871.     OSErr                        myErr = noErr;
  872.  
  873.     // get the movie's user data list
  874.     myUserData = GetMovieUserData(theMovie);
  875.     if (myUserData == NULL)
  876.         return(paramErr);
  877.     
  878.     // copy the specified text into a new handle
  879.     myHandle = NewHandleClear(myLength);
  880.     if (myHandle == NULL)
  881.         return(MemError());
  882.  
  883.     BlockMoveData(theText, *myHandle, myLength);
  884.  
  885.     // for simplicity, we assume that we want only one user data item of the specified type in the movie;
  886.     // as a result, we won't worry about overwriting any existing item of that type....
  887.     //
  888.     // if you need multiple user data items of a given type (for example, a copyright notice
  889.     // in several different languages), you would need to modify this code; this is left as an exercise
  890.     // for the reader....
  891.  
  892.     // add the data to the movie's user data
  893.     myErr = AddUserDataText(myUserData, myHandle, theType, myIndex + 1, smSystemScript);
  894.  
  895.     // clean up
  896.     DisposeHandle(myHandle);
  897.     return(myErr);
  898. }
  899.  
  900.  
  901. //////////
  902. //
  903. // QTUtils_AddCopyrightToMovie
  904. // Add a user data item containing the specified copyright text to a movie.
  905. //
  906. //////////
  907.  
  908. OSErr QTUtils_AddCopyrightToMovie (Movie theMovie, char *theText)
  909. {
  910.     return(QTUtils_AddUserDataTextToMovie(theMovie, theText, kUserDataTextCopyright));
  911. }
  912.  
  913.  
  914. //////////
  915. //
  916. // QTUtils_AddMovieNameToMovie
  917. // Add a user data item containing the specified name to a movie.
  918. //
  919. //////////
  920.  
  921. OSErr QTUtils_AddMovieNameToMovie (Movie theMovie, char *theText)
  922. {
  923.     return(QTUtils_AddUserDataTextToMovie(theMovie, theText, kUserDataTextFullName));
  924. }
  925.  
  926.  
  927. //////////
  928. //
  929. // QTUtils_AddMovieInfoToMovie
  930. // Add a user data item containing the specified information to a movie.
  931. //
  932. //////////
  933.  
  934. OSErr QTUtils_AddMovieInfoToMovie (Movie theMovie, char *theText)
  935. {
  936.     return(QTUtils_AddUserDataTextToMovie(theMovie, theText, kUserDataTextInformation));
  937. }
  938.  
  939.  
  940. //////////
  941. //
  942. // QTUtils_GetMovieFileLoopingInfo
  943. // Get the looping state of a movie file.
  944. //
  945. // A movie file can have information about its looping state in a user data item of type 'LOOP'.
  946. // If the movie doesn't contain an item of this type, then we'll assume that it isn't looping.
  947. // If it does contain an item of this type, then the item data (a long integer) is 0 for normal
  948. // looping and 1 for palindrome looping. Accordingly, this function returns the following values
  949. // in the theLoopInfo parameter:
  950. //
  951. //        0 == normal looping
  952. //        1 == palindrome looping
  953. //        2 == no looping
  954. //
  955. // Return an error if the movie has no looping state. In any case, return a meaningful looping state.
  956. //
  957. //////////
  958.  
  959. OSErr QTUtils_GetMovieFileLoopingInfo (Movie theMovie, long *theLoopInfo)
  960. {
  961.     UserData        myUserData = NULL;
  962.     long            myLoopInfo = kNoLooping;
  963.     OSErr            myErr = paramErr;
  964.  
  965.     // make sure we've got a movie
  966.     if (theMovie == NULL)
  967.         goto bail;
  968.         
  969.     // get the movie's user data list
  970.     myUserData = GetMovieUserData(theMovie);
  971.     if (myUserData != NULL) {
  972.         myErr = GetUserDataItem(myUserData, &myLoopInfo, sizeof(myLoopInfo), FOUR_CHAR_CODE('LOOP'), 0);
  973.         if (myErr == noErr)
  974.             myLoopInfo = EndianS32_BtoN(myLoopInfo);
  975.     }
  976.  
  977. bail:
  978.     *theLoopInfo = myLoopInfo;
  979.  
  980.     return(myErr);
  981. }
  982.  
  983.  
  984. //////////
  985. //
  986. // QTUtils_SetMovieFileLoopingInfo
  987. // Set the looping state for a movie file.
  988. //
  989. //////////
  990.  
  991. OSErr QTUtils_SetMovieFileLoopingInfo (Movie theMovie, long theLoopInfo)
  992. {
  993.     UserData        myUserData = NULL;
  994.     long            myLoopInfo;
  995.     short            myCount = 0;
  996.     OSErr            myErr = paramErr;
  997.  
  998.     // get the movie's user data
  999.     myUserData = GetMovieUserData(theMovie);
  1000.     if (myUserData == NULL)
  1001.         goto bail;
  1002.  
  1003.     // we want to end up with at most one user data item of type 'LOOP',
  1004.     // so let's remove any existing ones
  1005.     myCount = CountUserDataType(myUserData, FOUR_CHAR_CODE('LOOP'));
  1006.     while (myCount--)
  1007.         RemoveUserData(myUserData, FOUR_CHAR_CODE('LOOP'), 1);
  1008.  
  1009.     // make sure we're writing big-endian data
  1010.     myLoopInfo = EndianU32_NtoB(theLoopInfo);
  1011.     
  1012.     switch (theLoopInfo) {
  1013.         case kNormalLooping:
  1014.         case kPalindromeLooping:
  1015.             myErr = SetUserDataItem(myUserData, &myLoopInfo, sizeof(long), FOUR_CHAR_CODE('LOOP'), 0);
  1016.             break;
  1017.  
  1018.         case kNoLooping:
  1019.         default:
  1020.             myErr = noErr;
  1021.             break;
  1022.     }
  1023.  
  1024. bail:
  1025.     return(myErr);
  1026. }
  1027.  
  1028.  
  1029. //////////
  1030. //
  1031. // QTUtils_SetLoopingStateFromFile
  1032. // Set the looping state for a movie based on the looping information in the movie file.
  1033. //
  1034. //////////
  1035.  
  1036. OSErr QTUtils_SetLoopingStateFromFile (Movie theMovie, MovieController theMC)
  1037. {
  1038.     long             myLoopInfo = kNoLooping;
  1039.     OSErr            myErr = noErr;
  1040.  
  1041.     myErr = QTUtils_GetMovieFileLoopingInfo(theMovie, &myLoopInfo);
  1042.     switch (myLoopInfo) {
  1043.  
  1044.         case kNormalLooping:
  1045.             MCDoAction(theMC, mcActionSetLooping, (void *)true);
  1046.             MCDoAction(theMC, mcActionSetLoopIsPalindrome, (void *)false);
  1047.             break;
  1048.  
  1049.         case kPalindromeLooping:
  1050.             MCDoAction(theMC, mcActionSetLooping, (void *)true);
  1051.             MCDoAction(theMC, mcActionSetLoopIsPalindrome, (void *)true);
  1052.             break;
  1053.  
  1054.         case kNoLooping:
  1055.         default:
  1056.             MCDoAction(theMC, mcActionSetLooping, (void *)false);
  1057.             MCDoAction(theMC, mcActionSetLoopIsPalindrome, (void *)false);
  1058.             break;
  1059.     }
  1060.  
  1061.     return(myErr);
  1062. }
  1063.  
  1064.  
  1065. //////////
  1066. //
  1067. // QTUtils_MakeMovieLoop
  1068. // Set the specified movie to loop.
  1069. //
  1070. // Based on the function MakeMovieLoop by Kevin Marks.
  1071. //
  1072. //////////
  1073.  
  1074. OSErr QTUtils_MakeMovieLoop (Movie theMovie, Boolean isPalindrome)
  1075. {
  1076.     TimeBase        myTimeBase = NULL;
  1077.     long             myFlags = 0L;
  1078.     OSErr            myErr = paramErr;
  1079.  
  1080.     // make sure we've got a movie
  1081.     if (theMovie == NULL)
  1082.         goto bail;
  1083.     
  1084.     myErr = noErr;
  1085.         
  1086.     // set the movie's play hints to enhance looping performance
  1087.     SetMoviePlayHints(theMovie, hintsLoop, hintsLoop);
  1088.     
  1089.     // set the looping flag of the movie's time base
  1090.     myTimeBase = GetMovieTimeBase(theMovie);
  1091.     myFlags = GetTimeBaseFlags(myTimeBase);
  1092.     myFlags |= loopTimeBase;
  1093.     
  1094.     // set or clear the palindrome flag, depending on the specified setting
  1095.     if (isPalindrome)
  1096.         myFlags |= palindromeLoopTimeBase;
  1097.     else
  1098.         myFlags &= ~palindromeLoopTimeBase;
  1099.         
  1100.     SetTimeBaseFlags(myTimeBase, myFlags);
  1101.  
  1102. bail:
  1103.     return(myErr);
  1104. }
  1105.  
  1106.  
  1107. //////////
  1108. //
  1109. // QTUtils_GetWindowPositionFromFile
  1110. // Return, through thePoint, the stored position of the specified movie.
  1111. //
  1112. // Return an error if the movie has no stored position. In any case, return a meaningful position.
  1113. //
  1114. //////////
  1115.  
  1116. OSErr QTUtils_GetWindowPositionFromFile (Movie theMovie, Point *thePoint)
  1117. {
  1118.     UserData        myUserData = NULL;
  1119.     Point            myPoint = {kDefaultWindowX, kDefaultWindowY};
  1120.     OSErr            myErr = paramErr;
  1121.  
  1122.     // make sure we've got a movie
  1123.     if (theMovie == NULL)
  1124.         goto bail;
  1125.         
  1126.     // get the movie's user data list
  1127.     myUserData = GetMovieUserData(theMovie);
  1128.     if (myUserData != NULL) {
  1129.         myErr = GetUserDataItem(myUserData, &myPoint, sizeof(Point), FOUR_CHAR_CODE('WLOC'), 0);
  1130.         if (myErr == noErr) {
  1131.             myPoint.v = EndianS16_BtoN(myPoint.v);
  1132.             myPoint.h = EndianS16_BtoN(myPoint.h);
  1133.         }
  1134.     }
  1135.  
  1136. bail:
  1137.     *thePoint = myPoint;
  1138.  
  1139.     return(myErr);
  1140. }
  1141.  
  1142.  
  1143. //////////
  1144. //
  1145. // QTUtils_GetTrackName
  1146. // Get the name of the specified movie track.
  1147. //
  1148. // This routine is modelled on the one contained in Dispatch 2 from the Ice Floe;
  1149. // I've modified it to return a C string instead of a Pascal string.
  1150. //
  1151. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1152. //
  1153. //////////
  1154.  
  1155. char *QTUtils_GetTrackName (Track theTrack)
  1156. {
  1157.     UserData            myUserData;
  1158.     char                *myString = NULL;
  1159.      OSErr                myErr = noErr;
  1160.  
  1161.     // make sure we've got a track
  1162.     if (theTrack == NULL)
  1163.         return(NULL);
  1164.         
  1165.     // a track's name (if it has one) is stored in the track's user data
  1166.     myUserData = GetTrackUserData(theTrack);
  1167.     if (myUserData != NULL) {
  1168.         Handle            myHandle = NewHandle(0);
  1169.  
  1170.         // get the user data item of type kUserDataName;
  1171.         // the handle we pass to GetUserData is resized to contain the track name
  1172.         myErr = GetUserData(myUserData, myHandle, kUserDataName, 1);
  1173.         if (myErr == noErr) {
  1174.             long        myLength = GetHandleSize(myHandle);
  1175.  
  1176.             if (myLength > 0) {
  1177.                 myString = malloc(myLength + 1);
  1178.                 if (myString != NULL) {
  1179.                     memcpy(myString, *myHandle, myLength);
  1180.                     myString[myLength] = '\0';
  1181.                 }
  1182.             }            
  1183.         }    
  1184.  
  1185.         DisposeHandle(myHandle);
  1186.     }
  1187.  
  1188.     return(myString);
  1189. }
  1190.  
  1191.  
  1192. //////////
  1193. //
  1194. // QTUtils_SetTrackName
  1195. // Set the name of the specified movie track.
  1196. //
  1197. // This function adds the specified text to the track's user data;
  1198. // the updated user data is written to the movie file when the movie is next updated
  1199. // (by calling UpdateMovieResource).
  1200. //
  1201. //////////
  1202.  
  1203. OSErr QTUtils_SetTrackName (Track theTrack, char *theText)
  1204. {
  1205.     UserData            myUserData;
  1206.     OSErr                myErr = noErr;
  1207.  
  1208.     // make sure we've got a track and a name
  1209.     if ((theTrack == NULL) || (theText == NULL))
  1210.         return(paramErr);
  1211.         
  1212.     // get the track's user data list
  1213.     myUserData = GetTrackUserData(theTrack);
  1214.     if (myUserData == NULL)
  1215.         return(paramErr);
  1216.     
  1217.     // remove any existing track name
  1218.     while (RemoveUserData(myUserData, kUserDataName, 1) == noErr)
  1219.         ;
  1220.  
  1221.     myErr = SetUserDataItem(myUserData, theText, strlen(theText), kUserDataName, 0);
  1222.  
  1223.     return(myErr);
  1224. }
  1225.  
  1226.  
  1227. //////////
  1228. //
  1229. // QTUtils_MakeTrackNameByType
  1230. // Create a (unique) name for the specified track, based on the track's type.
  1231. //
  1232. // Given a movie track, this routine constructs a name for that track based on
  1233. // the media type of that track. For instance, if the track is a sound track,
  1234. // this routine returns the name "Sound". However, if there is more than one
  1235. // track of that media type, then this routine numbers the track names. So, if
  1236. // there are two sound tracks, this routine names them "Sound 1" and "Sound 2".
  1237. //
  1238. // This routine is modelled on the one contained in Dispatch 2 from the Ice Floe;
  1239. // I've modified it to return a C string instead of a Pascal string.
  1240. //
  1241. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1242. //
  1243. //////////
  1244.  
  1245. char *QTUtils_MakeTrackNameByType (Track theTrack)
  1246. {
  1247.     Media                myMedia;
  1248.     char                *myString = NULL;
  1249.      ComponentResult        myErr = noErr;
  1250.  
  1251.     // make sure we've got a track
  1252.     if (theTrack == NULL)
  1253.         return(NULL);
  1254.     
  1255.     myMedia = GetTrackMedia(theTrack);
  1256.     if (myMedia != NULL) {
  1257.         MediaHandler    myMediaHandler = GetMediaHandler(myMedia);
  1258.         OSType            myMediaType;
  1259.         Str255            myName;
  1260.  
  1261.         // get the media type of the track
  1262.         GetMediaHandlerDescription(myMedia, &myMediaType, NULL, NULL);
  1263.         
  1264.         // get the text of the media type
  1265.         myErr = MediaGetName(myMediaHandler, myName, 0, NULL);
  1266.         if (myErr == noErr) {
  1267.             
  1268.             // determine whether there's more than one track with this media type
  1269.             if (GetMovieIndTrackType(GetTrackMovie(theTrack), 2, myMediaType, movieTrackMediaType) != NULL) {
  1270.  
  1271.                 // add an index number to the track type string we constructed above
  1272.                 long    myIndex = 1;
  1273.                 Str255    myNumString;
  1274.  
  1275.                 while (GetMovieIndTrackType(GetTrackMovie(theTrack), myIndex, myMediaType, movieTrackMediaType) != theTrack)
  1276.                    myIndex++;
  1277.  
  1278.                 NumToString(myIndex, myNumString);
  1279.                 myName[++myName[0]] = ' ';
  1280.                 BlockMoveData(&myNumString[1], &myName[myName[0] + 1], myNumString[0]);
  1281.                 myName[0] += myNumString[0];
  1282.             }
  1283.  
  1284.             // now copy the string data from the Pascal string to a C string
  1285.             if (myName[0] > 0) {
  1286.                 myString = malloc(myName[0] + 1);
  1287.                 if (myString != NULL) {
  1288.                     memcpy(myString, &myName[1], myName[0]);
  1289.                     myString[myName[0]] = '\0';
  1290.                 }
  1291.             }            
  1292.         }
  1293.     }
  1294.  
  1295.     return(myString);
  1296. }
  1297.  
  1298.  
  1299. //////////
  1300. //
  1301. // QTUtils_IsImageFile
  1302. // Is the specified file an image file?
  1303. //
  1304. //////////
  1305.  
  1306. Boolean QTUtils_IsImageFile (FSSpec *theFSSpec)
  1307. {    
  1308.     GraphicsImportComponent        myImporter = NULL;
  1309.  
  1310.     GetGraphicsImporterForFile(theFSSpec, &myImporter);
  1311.     if (myImporter != NULL)
  1312.         CloseComponent(myImporter);
  1313.  
  1314.     return(myImporter != NULL);
  1315. }
  1316.  
  1317.  
  1318. //////////
  1319. //
  1320. // QTUtils_IsMovieFile
  1321. // Is the specified file a file that can be opened by QuickTime as a movie?
  1322. //
  1323. //////////
  1324.  
  1325. Boolean QTUtils_IsMovieFile (FSSpec *theFSSpec)
  1326. {    
  1327.     Boolean                        isMovieFile = false;
  1328.     AliasHandle                    myAlias = NULL;
  1329.     Component                    myImporter = NULL;
  1330.     FInfo                        myFinderInfo;
  1331.     OSErr                        myErr = noErr;
  1332.             
  1333.     // see whether the file type is MovieFileType; to do this, get the Finder information
  1334.     myErr = FSpGetFInfo(theFSSpec, &myFinderInfo);    
  1335.     if (myErr == noErr)
  1336.         if (myFinderInfo.fdType == kQTFileTypeMovie)
  1337.             return(true);
  1338.  
  1339.     // if it isn't a movie file, see whether the file can be imported as a movie
  1340.     myErr = QTNewAlias(theFSSpec, &myAlias, true);
  1341.     if (myErr == noErr) {
  1342.         if (myAlias != NULL) {
  1343.             myErr = GetMovieImporterForDataRef(rAliasType, (Handle)myAlias, kGetMovieImporterDontConsiderGraphicsImporters, &myImporter);
  1344.             DisposeHandle((Handle)myAlias);
  1345.         }
  1346.     }
  1347.         
  1348.     if ((myErr == noErr) && (myImporter != NULL))        // this file is a movie file
  1349.         isMovieFile = true;
  1350.  
  1351.     return(isMovieFile);
  1352. }
  1353.  
  1354.  
  1355. //////////
  1356. //
  1357. // QTUtils_ConvertFloatToBigEndian
  1358. // Convert the specified floating-point number to big-endian format.
  1359. //
  1360. //////////
  1361.  
  1362. void QTUtils_ConvertFloatToBigEndian (float *theFloat)
  1363. {
  1364.     unsigned long        *myLongPtr;
  1365.     
  1366.     myLongPtr = (unsigned long *)theFloat;
  1367.     *myLongPtr = EndianU32_NtoB(*myLongPtr);
  1368. }
  1369.  
  1370.  
  1371. //////////
  1372. //
  1373. // QTUtils_ConvertCToPascalString
  1374. // Convert a C string into a Pascal string.
  1375. //
  1376. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1377. //
  1378. //////////
  1379.  
  1380. StringPtr QTUtils_ConvertCToPascalString (char *theString)
  1381. {
  1382.     StringPtr    myString = malloc(strlen(theString) + 1);
  1383.     short        myIndex = 0;
  1384.  
  1385.     while (theString[myIndex] != '\0') {
  1386.         myString[myIndex + 1] = theString[myIndex];
  1387.         myIndex++;
  1388.     }
  1389.     
  1390.     myString[0] = (unsigned char)myIndex;
  1391.     
  1392.     return(myString);
  1393. }
  1394.  
  1395.  
  1396. //////////
  1397. //
  1398. // QTUtils_ConvertPascalToCString
  1399. // Convert a Pascal string into a C string.
  1400. //
  1401. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1402. //
  1403. //////////
  1404.  
  1405. char *QTUtils_ConvertPascalToCString (StringPtr theString)
  1406. {
  1407.     char         *myString = malloc(theString[0] + 1);
  1408.     short        myIndex = 0;
  1409.  
  1410.     for (myIndex = 0; myIndex < theString[0]; myIndex++)
  1411.         myString[myIndex] = theString[myIndex + 1];
  1412.     
  1413.     myString[theString[0]] = '\0';
  1414.     
  1415.     return(myString);
  1416. }
  1417.  
  1418.  
  1419. //////////
  1420. //
  1421. // QTUtils_DeleteAllReferencesToTrack
  1422. // Delete all existing track references to the specified track.
  1423. //
  1424. //////////
  1425.  
  1426. OSErr QTUtils_DeleteAllReferencesToTrack (Track theTrack)
  1427. {
  1428.     Movie                myMovie = NULL;
  1429.     Track                myTrack = NULL;
  1430.     long                myTrackCount = 0L;
  1431.     long                myTrRefCount = 0L;
  1432.     long                myTrackIndex;
  1433.     long                myTrRefIndex;
  1434.     OSErr                myErr = noErr;
  1435.  
  1436.     myMovie = GetTrackMovie(theTrack);
  1437.     if (myMovie == NULL)
  1438.         return(paramErr);
  1439.  
  1440.     // iterate thru all the tracks in the movie (that are different from the specified track)
  1441.     myTrackCount = GetMovieTrackCount(myMovie);
  1442.     for (myTrackIndex = 1; myTrackIndex <= myTrackCount; myTrackIndex++) {
  1443.         myTrack = GetMovieIndTrack(myMovie, myTrackIndex);
  1444.         if ((myTrack != NULL) && (myTrack != theTrack)) {
  1445.             OSType        myType = 0L;
  1446.     
  1447.             // iterate thru all track reference types contained in the current track
  1448.             myType = GetNextTrackReferenceType(myTrack, myType);
  1449.             while (myType != 0L) {
  1450.  
  1451.                 // iterate thru all track references of the current type;
  1452.                 // note that we count down to 1, since DeleteTrackReference will cause
  1453.                 // any higher-indexed track references to be renumbered
  1454.                 myTrRefCount = GetTrackReferenceCount(myTrack, myType);
  1455.                 for (myTrRefIndex = myTrRefCount; myTrRefIndex >= 1; myTrRefIndex--) {
  1456.                     Track    myRefTrack = NULL;
  1457.  
  1458.                     myRefTrack = GetTrackReference(myTrack, myType, myTrRefIndex);
  1459.                     if (myRefTrack == theTrack)
  1460.                         myErr = DeleteTrackReference(myTrack, myType, myTrRefIndex);
  1461.                 }
  1462.  
  1463.                 myType = GetNextTrackReferenceType(myTrack, myType);
  1464.             }
  1465.         }
  1466.     }
  1467.  
  1468.     return(myErr);
  1469. }
  1470.  
  1471.  
  1472. //////////
  1473. //
  1474. // QTUtils_GetFrameDuration
  1475. // Get the duration of the first sample frame in the specified movie track.
  1476. //
  1477. //////////
  1478.  
  1479. TimeValue QTUtils_GetFrameDuration (Track theTrack)
  1480. {    
  1481.     TimeValue    mySampleDuration;
  1482.     OSErr        myErr = noErr;
  1483.  
  1484.     myErr = GetMediaSample(    GetTrackMedia(theTrack),
  1485.                             NULL,         // don't return sample data
  1486.                             0,
  1487.                             NULL,        // don't return number of bytes of sample data returned
  1488.                             0,
  1489.                             NULL,
  1490.                             &mySampleDuration,
  1491.                             NULL,        // don't return sample description
  1492.                             NULL,        // don't return sample description index
  1493.                             0,            // no max number of samples
  1494.                             NULL,        // don't return number of samples returned
  1495.                             NULL);        // don't return sample flags
  1496.  
  1497.     // make sure we return a legitimate value even if GetMediaSample encounters an error
  1498.     if (myErr != noErr)
  1499.         mySampleDuration = 0;
  1500.  
  1501.     return(mySampleDuration);
  1502. }
  1503.  
  1504.  
  1505. //////////
  1506. //
  1507. // QTUtils_GetFrameCount
  1508. // Get the number of frames in the specified movie track. We return the value -1 if
  1509. // an error occurs and we cannot determine the number of frames in the track.
  1510. //
  1511. // Based (loosely) on frame-counting code in ConvertToMovie Jr.c.
  1512. // 
  1513. // We count the frames in the track by stepping through all of its interesting times
  1514. // (the places where the track displays a new sample).
  1515. //
  1516. //////////
  1517.  
  1518. long QTUtils_GetFrameCount (Track theTrack)
  1519. {    
  1520.     long        myCount = -1;
  1521.     short        myFlags;
  1522.     TimeValue    myTime = 0;
  1523.     
  1524.     if (theTrack == NULL)
  1525.         goto bail;
  1526.         
  1527.     // we want to begin with the first frame (sample) in the track
  1528.     myFlags = nextTimeMediaSample + nextTimeEdgeOK;
  1529.  
  1530.     while (myTime >= 0) {
  1531.         myCount++;
  1532.         
  1533.         // look for the next frame in the track; when there are no more frames,
  1534.         // myTime is set to -1, so we'll exit the while loop
  1535.         GetTrackNextInterestingTime(theTrack, myFlags, myTime, fixed1, &myTime, NULL);
  1536.         
  1537.         // after the first interesting time, don't include the time we're currently at
  1538.         myFlags = nextTimeStep;
  1539.     }
  1540.  
  1541. bail:
  1542.     return(myCount);
  1543. }
  1544.  
  1545.  
  1546. //////////
  1547. //
  1548. // QTUtils_GetMaxWindowDepth
  1549. // Get the deepest pixel type and size of the screen area intersected by a specified window.
  1550. //
  1551. //////////
  1552.  
  1553. #if TARGET_OS_MAC
  1554. void QTUtils_GetMaxWindowDepth (CWindowPtr theWindow, short *thePixelType, short *thePixelSize)
  1555. {
  1556.     Rect            myRect;
  1557.     Point            myPoint = {0, 0};
  1558.     
  1559.     // initialize returned values 
  1560.     *thePixelType = k1MonochromePixelFormat;
  1561.     *thePixelSize = 0;
  1562.  
  1563.     if (theWindow == NULL)
  1564.         return;
  1565.  
  1566.     GetWindowPortBounds(theWindow, &myRect);
  1567.  
  1568.     // assume the window is the current port
  1569.     LocalToGlobal(&myPoint);
  1570.  
  1571.     // offset the rectangle to global coordinates
  1572.     MacOffsetRect(&myRect, myPoint.h, myPoint.v);
  1573.     
  1574.     // get the max data for the global rectangle
  1575.     QTUtils_GetMaxScreenDepth(&myRect, thePixelType, thePixelSize);
  1576. }
  1577. #endif
  1578.  
  1579. //////////
  1580. //
  1581. // QTUtils_GetMaxScreenDepth
  1582. // Get the deepest pixel type and size of the screen area intersected by a specified rectangle.
  1583. //
  1584. //////////
  1585.  
  1586. void QTUtils_GetMaxScreenDepth (Rect *theGlobalRect, short *thePixelType, short *thePixelSize)
  1587. {
  1588.     GDHandle        myGDevice = NULL;
  1589.     PixMapHandle    myPixMap = NULL;
  1590.  
  1591.     myGDevice = GetMaxDevice(theGlobalRect);    // get the max device
  1592.     if (myGDevice != NULL) {
  1593.         // get the pixmap for the max device
  1594.         myPixMap = (**myGDevice).gdPMap;
  1595.         if (myPixMap != NULL) {
  1596.             // extract the interesting info from the pixmap of the device
  1597.             *thePixelType = (**myPixMap).pixelType;
  1598.             *thePixelSize = (**myPixMap).pixelSize;
  1599.         }
  1600.     }
  1601. }
  1602.  
  1603.  
  1604. //////////
  1605. //
  1606. // QTUtils_GetUsersConnectionSpeed
  1607. // Return the connection speed selected by the user in the QuickTime Settings control panel;
  1608. // return 0 if the user's QuickTime preferences cannot be read.
  1609. //
  1610. // Based on code in Ice Floe Dispatch 17 by Mike Dodd.
  1611. //
  1612. //////////
  1613.  
  1614. long QTUtils_GetUsersConnectionSpeed (void)
  1615. {
  1616.     QTAtomContainer                    myPrefsContainer = NULL;
  1617.     QTAtom                            myPrefsAtom = 0;
  1618.     ConnectionSpeedPrefsRecord        myPrefsRec;
  1619.     long                            myDataSize = 0L;
  1620.     long                            mySpeed = 0L;
  1621.     Ptr                                myAtomData = NULL;
  1622.     OSErr                            myErr = noErr;
  1623.  
  1624.     // you can retrieve the user's QuickTime preferences by calling GetQuickTimePreference;
  1625.     // the first parameter indicates the type of preference you want information about, and
  1626.     // the second parameter is an atom container that contains the returned preference data 
  1627.     myErr = GetQuickTimePreference(ConnectionSpeedPrefsType, &myPrefsContainer);
  1628.     if (myErr == noErr) {
  1629.             
  1630.         // find the atom of the desired type
  1631.         myPrefsAtom = QTFindChildByID(myPrefsContainer, kParentAtomIsContainer, ConnectionSpeedPrefsType, 1, NULL);
  1632.         if (myPrefsAtom == 0) {
  1633.             // we did not find any such atom in the returned atom container, so we'll
  1634.             // return a default connection speed setting of 28.8K bytes per second
  1635.             mySpeed = kDataRate288ModemRate;
  1636.         } else {
  1637.             // we found the desired atom in the returned atom container;
  1638.             // read the data contained in that atom and verify that the data is of the
  1639.             // size we are expecting
  1640.             QTGetAtomDataPtr(myPrefsContainer, myPrefsAtom, &myDataSize, &myAtomData);
  1641.             
  1642.             if (myDataSize != sizeof(ConnectionSpeedPrefsRecord)) {
  1643.                 // the data in the atom isn't the right size, so it must be corrupt;
  1644.                 // return a default connection speed setting of 28.8K bytes per second
  1645.                 mySpeed = kDataRate288ModemRate;
  1646.             } else {
  1647.                 // everything is fine: read the connection speed
  1648.                 
  1649.                 // NOTE: the data in this atom is native-endian, so we do not need to
  1650.                 // perform any endian-swapping when extracting the speed from the atom.
  1651.                 // (This is an exception to the rule that data in atom containers is
  1652.                 // always big-endian.)
  1653.                 myPrefsRec = *(ConnectionSpeedPrefsRecord *)myAtomData;
  1654.                 mySpeed = myPrefsRec.connectionSpeed;
  1655.             }
  1656.         }
  1657.  
  1658.         QTDisposeAtomContainer(myPrefsContainer);
  1659.     }
  1660.     
  1661.     return(mySpeed);
  1662. }
  1663.  
  1664.  
  1665. //////////
  1666. //
  1667. // QTUtils_SetUsersConnectionSpeed
  1668. // Set the connection speed in the QuickTime Settings control panel to the specified value.
  1669. //
  1670. // NOTE: In general, you should let the user decide the connection speed (using the QuickTime
  1671. // Settings control panel). In some cases, however, you might need to do this programmatically.
  1672. // Also, you should in general use values for theSpeed that are enumerated in the header file
  1673. // MoviesFormat.h.
  1674. //
  1675. // Based on code in Ice Floe Dispatch 17 by Mike Dodd.
  1676. //
  1677. //////////
  1678.  
  1679. OSErr QTUtils_SetUsersConnectionSpeed (long theSpeed)
  1680. {
  1681.     QTAtomContainer                    myPrefsContainer = NULL;
  1682.     QTAtom                            myPrefsAtom = 0;
  1683.     ConnectionSpeedPrefsRecord        myPrefsRec;
  1684.     OSErr                            myErr = noErr;
  1685.  
  1686.     myErr = QTNewAtomContainer(&myPrefsContainer);
  1687.     if (myErr == noErr) {
  1688.         // NOTE: the data in this atom is native-endian, so we do not need to
  1689.         // perform any endian-swapping when inserting the speed into the atom.
  1690.         // (This is an exception to the rule that data in atom containers is
  1691.         // always big-endian.)
  1692.         myPrefsRec.connectionSpeed = theSpeed;
  1693.         
  1694.         myErr = QTInsertChild(myPrefsContainer, kParentAtomIsContainer, ConnectionSpeedPrefsType, 1, 0, sizeof(ConnectionSpeedPrefsRecord), &myPrefsRec, &myPrefsAtom);
  1695.         if (myErr == noErr)
  1696.             myErr = SetQuickTimePreference(ConnectionSpeedPrefsType, myPrefsContainer);
  1697.             
  1698.         QTDisposeAtomContainer(myPrefsContainer);
  1699.     }
  1700.  
  1701.     return(myErr);
  1702. }
  1703.  
  1704.  
  1705. #if CONTENT_RATING_AVAIL
  1706. //////////
  1707. //
  1708. // QTUtils_GetUsersContentRating
  1709. // Return, through the function's parameters, the content rating and acceptable content types
  1710. // selected by the user in the QuickTime Settings control panel; return an error if the user's
  1711. // QuickTime preferences cannot be read.
  1712. //
  1713. // Based on QTUtils_GetUsersConnectionSpeed.
  1714. //
  1715. //////////
  1716.  
  1717. OSErr QTUtils_GetUsersContentRating (UInt32 *theType, UInt16 *theRating)
  1718. {
  1719.     QTAtomContainer                    myPrefsContainer = NULL;
  1720.     QTAtom                            myPrefsAtom = 0;
  1721.     ContentRatingPrefsRecord        myContentRec;
  1722.     long                            myDataSize = 0L;
  1723.     Ptr                                myAtomData = NULL;
  1724.     OSErr                            myErr = noErr;
  1725.  
  1726.     // you can retrieve the user's QuickTime preferences by calling GetQuickTimePreference;
  1727.     // the first parameter indicates the type of preference you want information about, and
  1728.     // the second parameter is an atom container that contains the returned preference data 
  1729.     myErr = GetQuickTimePreference(kContentRatingPrefsType, &myPrefsContainer);
  1730.     if (myErr == noErr) {
  1731.             
  1732.         // find the atom of the desired type
  1733.         myPrefsAtom = QTFindChildByID(myPrefsContainer, kParentAtomIsContainer, kContentRatingPrefsType, 1, NULL);
  1734.         if (myPrefsAtom == 0) {
  1735.             // we did not find any such atom in the returned atom container, so we'll
  1736.             // return default settings
  1737.             *theType = 0L;
  1738.             *theRating = kQTContentTVYRating;
  1739.         } else {
  1740.             // we found the desired atom in the returned atom container;
  1741.             // read the data contained in that atom and verify that the data is of the
  1742.             // size we are expecting
  1743.             myErr = QTGetAtomDataPtr(myPrefsContainer, myPrefsAtom, &myDataSize, &myAtomData);
  1744.             
  1745.             if (myDataSize != sizeof(ContentRatingPrefsRecord)) {
  1746.                 // the data in the atom isn't the right size, so it must be corrupt;
  1747.                 // return default settings
  1748.                 *theType = 0L;
  1749.                 *theRating = kQTContentTVYRating;
  1750.             } else {
  1751.                 // everything is fine: read the content information
  1752.                 
  1753.                 // NOTE: the data in this atom is native-endian, so we do not need to
  1754.                 // perform any endian-swapping when extracting the data from the atom.
  1755.                 // (This is an exception to the rule that data in atom containers is
  1756.                 // always big-endian.)
  1757.                 
  1758.                 // WARNING: the format of the data in a content rating atom is, to my
  1759.                 // knowledge, currently undocumented; the following method of extracting
  1760.                 // that info is based on empirical investigation.
  1761.                 myContentRec = *(ContentRatingPrefsRecord *)myAtomData;
  1762.                 *theType = (UInt32)(~(myContentRec.fContentTypes) & 0x00ff);
  1763.                 *theRating = myContentRec.fContentRating;
  1764.             }
  1765.         }
  1766.  
  1767.         QTDisposeAtomContainer(myPrefsContainer);
  1768.     }
  1769.     
  1770.     return(myErr);
  1771. }
  1772. #endif    // #if CONTENT_RATING_AVAIL
  1773.  
  1774.  
  1775. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1776. //
  1777. // Controller utilities.
  1778. //
  1779. // Use these functions to manipulate movie controllers.
  1780. //
  1781. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1782.  
  1783. //////////
  1784. //
  1785. // QTUtils_GetControllerType
  1786. // Get the controller type of the specified movie.
  1787. //
  1788. //////////
  1789.  
  1790. OSType QTUtils_GetControllerType (Movie theMovie) 
  1791. {
  1792.     UserData        myUserData = NULL;
  1793.     OSType            myType = kUnknownType;
  1794.     OSErr            myErr = noErr;
  1795.     
  1796.     // make sure we've got a movie
  1797.     if (theMovie == NULL)
  1798.         return(myType);
  1799.         
  1800.     myUserData = GetMovieUserData(theMovie);
  1801.     if (myUserData != NULL) {
  1802.         myErr = GetUserDataItem(myUserData, &myType, sizeof(myType), kUserDataMovieControllerType, 0);
  1803.         if (myErr == noErr)
  1804.             myType = EndianU32_BtoN(myType);
  1805.     }
  1806.     
  1807.     return(myType);
  1808. }
  1809.  
  1810.  
  1811. //////////
  1812. //
  1813. // QTUtils_SetControllerType
  1814. // Set the controller type of the specified movie.
  1815. //
  1816. // This function adds an item to the movie's user data;
  1817. // the updated user data is written to the movie file when the movie is next updated
  1818. // (by calling AddMovieResource or UpdateMovieResource).
  1819. //
  1820. // NOTE: This function is intended to set the controller type of a movie you're building;
  1821. // to change the controller of an open movie, use QTUtils_ChangeControllerType.
  1822. //
  1823. //////////
  1824.  
  1825. OSErr QTUtils_SetControllerType (Movie theMovie, OSType theType)
  1826. {
  1827.     UserData        myUserData;
  1828.     OSErr            myErr = noErr;
  1829.  
  1830.     // make sure we've got a movie
  1831.     if (theMovie == NULL)
  1832.         return(paramErr);
  1833.         
  1834.     // get the movie's user data list
  1835.     myUserData = GetMovieUserData(theMovie);
  1836.     if (myUserData == NULL)
  1837.         return(paramErr);
  1838.     
  1839.     theType = EndianU32_NtoB(theType);
  1840.     myErr = SetUserDataItem(myUserData, &theType, sizeof(theType), kUserDataMovieControllerType, 0);
  1841.  
  1842.     return(myErr);
  1843. }
  1844.  
  1845.  
  1846. //////////
  1847. //
  1848. // QTUtils_ChangeControllerType
  1849. // Change the controller type of the movie that uses the specified controller, "on the fly",
  1850. // and return the new movie controller to the caller; if for some reason we cannot create a
  1851. // new movie controller, return NULL.
  1852. //
  1853. //////////
  1854.  
  1855. MovieController QTUtils_ChangeControllerType (MovieController theMC, OSType theType, long theFlags)
  1856. {
  1857.     MovieController        myMC = NULL;
  1858.     Movie                myMovie = NULL;
  1859.     Rect                myRect;
  1860.     OSErr                myErr = noErr;
  1861.  
  1862.     // make sure we've got a movie controller
  1863.     if (theMC == NULL)
  1864.         return(NULL);
  1865.     
  1866.     // get the movie associated with that controller
  1867.     myMovie = MCGetMovie(theMC);
  1868.     if (myMovie == NULL)
  1869.         return(NULL);
  1870.         
  1871.     GetMovieBox(myMovie, &myRect);
  1872.  
  1873.     // set the new controller type in the movie's user data list
  1874.     myErr = QTUtils_SetControllerType(myMovie, theType);
  1875.     if (myErr != noErr)
  1876.         return(NULL);
  1877.  
  1878.     // dispose of the existing controller
  1879.     DisposeMovieController(theMC);
  1880.     
  1881.     // create a new controller of the specified type
  1882.     myMC = NewMovieController(myMovie, &myRect, theFlags);
  1883.  
  1884.     return(myMC);
  1885. }
  1886.  
  1887.  
  1888. #endif    // ifndef __QTUtilities__